package edu.usc.cs523.server;

import com.jme3.app.SimpleApplication;
import com.jme3.math.Vector3f;
import com.jme3.network.ConnectionListener;
import com.jme3.network.HostedConnection;
import com.jme3.network.Message;
import com.jme3.network.MessageListener;
import com.jme3.network.Network;
import com.jme3.network.Server;
import com.jme3.network.serializing.Serializer;
import com.jme3.renderer.RenderManager;
import com.jme3.system.JmeContext;
import edu.usc.cs523.client.MessageFactory;
import edu.usc.cs523.client.Rival;
import edu.usc.cs523.settings.Global;
import edu.usc.cs523.util.CeceMessage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * test
 * @author normenhansen
 */
public class ServerMain extends SimpleApplication implements MessageListener<HostedConnection>, ConnectionListener {

    private Server server;
    private int NUM_PLAYER;
    private ArrayList<Rival> players;

    @Override
    public void simpleInitApp() {
        try {
            server = Network.createServer(Global.server_port_number);
            //register message class
            Serializer.registerClass(CeceMessage.class);
            //then register the message listener
            server.addMessageListener(this, CeceMessage.class);
            //then set the connection listener
            server.addConnectionListener(this);
            //then start the server
            server.start();

            //initial variables
            NUM_PLAYER = 0;
            players = new ArrayList<Rival>();
        } catch (IOException ex) {
            Logger.getLogger(ServerMain.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }

    @Override
    public void destroy() {
        server.close();
        super.destroy();
    }

    public void messageReceived(HostedConnection source, Message m) {
        if (m instanceof CeceMessage) {
            CeceMessage message = (CeceMessage) m;
            System.out.println("receive: " + m.toString());
            switch (message.getAction()) {
                case Global.ACTION_CONNECT:
                    connectAction(source, message);
                    break;
                case Global.ACTION_ACTION:
                    doActionAction(source, message);
                    break;
                case Global.ACTION_DISCONNECT:
                    disconnectAction(source, message);
                    break;
                case Global.ACTION_CHANGE:
                    changeAction(source, message);
                    break;
            }

            //becky, I commented this code for broadcast one message to all the clients.
            //            server.broadcast(new CeceMessage());
        }
    }

    public void connectionAdded(Server server, HostedConnection conn) {
    }

    public void connectionRemoved(Server server, HostedConnection conn) {
        int cid = conn.getId();
        for (int i = 0; i < players.size(); i++) {
            Rival player = players.get(i);
            if (player.getId() == cid) {
                players.remove(player);
                CeceMessage disconnectMessage = MessageFactory.getInstance().getDisconnectMessage(cid);
                server.broadcast(disconnectMessage);
                System.out.println("num reduced");
                NUM_PLAYER--;
            }
        }
    }

    public static void main(String[] args) {
        ServerMain app = new ServerMain();
        app.start(JmeContext.Type.Headless);
    }

    private void connectAction(HostedConnection source, CeceMessage message) {
        if (NUM_PLAYER == 0) {
            CeceMessage m = MessageFactory.getInstance().getConnectMessage(source.getId(), message.getMessage());
            server.broadcast(m);

            Rival player = new Rival(null);
            player.setId(source.getId());
            player.setPosition(Global.START_POSITION);
            player.setDirection(Global.START_DIRECTION);
            player.setModel_num(message.getMessage());
            System.out.println("user one added");
            System.out.println("connect:" + m.toString());
            players.add(player);
            NUM_PLAYER = 1;
        } else {
            if (NUM_PLAYER == 1) {
                System.out.println("user two added");
                CeceMessage m = MessageFactory.getInstance().getConnectMessage(source.getId(), message.getMessage());
                server.broadcast(m);
                System.out.println("connect:" + m.toString());

                CeceMessage m2 = MessageFactory.getInstance().getStatusMessage(players.get(0).getDirection(),
                        players.get(0).getPosition(),
                        players.get(0).getId(), players.get(0).getModel_num());
                server.broadcast(m2);
                System.out.println("status:" + m2.toString());

                Rival player = new Rival(null);
                player.setId(source.getId());
                player.setPosition(Global.START_POSITION);
                player.setDirection(Global.START_DIRECTION);
                player.setModel_num(message.getMessage());

                players.add(player);
                NUM_PLAYER = 2;
            }
        }
    }

    private void doActionAction(HostedConnection source, CeceMessage message) {
        CeceMessage m2 = null;
        Vector3f pos = message.getPosition();
        Vector3f dir = message.getDirection();
        switch (message.getMessage()) {
            case Global.MOVE_FORWARD:
                m2 = MessageFactory.getInstance().getMoveForwardMessage(message.getId(), false, pos, dir);
                break;
            case Global.MOVE_BACK:
                m2 = MessageFactory.getInstance().getMoveBackMessage(message.getId(), false, pos, dir);
                break;
            case Global.MOVE_LEFT:
                m2 = MessageFactory.getInstance().getMoveLeftMessage(message.getId(), false, pos, dir);
                break;
            case Global.MOVE_RIGHT:
                m2 = MessageFactory.getInstance().getMoveRightMessage(message.getId(), false, pos, dir);
                break;
            case Global.JUMP:
                m2 = MessageFactory.getInstance().getJumpMessage(message.getId(), false, pos);
                break;
            case Global.MOVE_DIRECTION:
                m2 = MessageFactory.getInstance().getMoveDirectionMessage(message.getId(), false, pos, dir);
                break;
        }
        //todo change the status of server side

        server.broadcast(m2);
//        System.out.println("broad cast:" + m2.toString());
    }

    private void disconnectAction(HostedConnection source, CeceMessage message) {
    }

    private void changeAction(HostedConnection source, CeceMessage message) {
        server.broadcast(message);
//        System.out.println("broad cast:" + message.toString());
    }
}
